/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.base.service.impl;

import com.xy.biz.base.client.DictClient;
import com.xy.biz.base.domain.bo.GoodsBO;
import com.xy.biz.base.domain.enums.ProductionDateUnitEnum;
import com.xy.biz.base.domain.enums.QualityGuaranteePeriodUnitEnum;
import com.xy.biz.base.domain.query.GoodsQuery;
import com.xy.biz.base.manager.GoodsManager;
import com.xy.biz.base.service.GoodsService;
import com.xy.lang.domain.Result;
import com.xy.lang.enums.ApplyStatusEnum;
import com.xy.tool.context.UserContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author zgy
 * @date 2021-9-22
 */
@Service
public class GoodsServiceImpl implements GoodsService {

	@Autowired
	private GoodsManager goodsManager;
	@Autowired
	private DictClient dictClient;
	
	@Override
	public Result<?> saveGoods(GoodsBO goodsBO) {
		return saveAllGoods(Arrays.asList(goodsBO));
	}
	
	@Override
	public Result<?> saveAllGoods(Collection<GoodsBO> collection) {
		LocalDateTime now = LocalDateTime.now();
		SaveGoodsContext saveGoodsContext = new SaveGoodsContext();
		collection.forEach(goodsBO -> {
			buildGoodsForSave(saveGoodsContext, goodsBO, now);
		});
		int affectedRows = goodsManager.saveAllGoods(collection);
		if (affectedRows > 0) {
			return Result.success();
		}
		return Result.ofErrorRowsAffected();
	}

	class SaveGoodsContext {
		private Map<String, String> goodsQualitySetting;
		private Integer defaultQualityGuaranteePeriod;
		private Integer defaultProductionDateLower;
		private Integer defaultProductionDateUpper;

		public SaveGoodsContext() {
			goodsQualitySetting = dictClient.mapDict("goods_quality_setting");
		}

		public Integer getDefaultQualityGuaranteePeriod() {
			if(defaultQualityGuaranteePeriod == null) {
				try {
					defaultQualityGuaranteePeriod = Integer.parseInt(goodsQualitySetting.get("defaultQualityGuaranteePeriod"));
				} catch (NumberFormatException e) {
					defaultQualityGuaranteePeriod = 1;
				}
			}

			return defaultQualityGuaranteePeriod;
		}

		public QualityGuaranteePeriodUnitEnum getDefaultQualityGuaranteePeriodUnit() {
			return QualityGuaranteePeriodUnitEnum.YEAR;
		}

		public Integer getDefaultProductionDateLower() {
			if(defaultProductionDateLower == null) {
				try {
					defaultProductionDateLower = Integer.parseInt(goodsQualitySetting.get("defaultProductionDateLower"));
				} catch (NumberFormatException e) {
					defaultProductionDateLower = 1;
				}
			}

			return defaultProductionDateLower;
		}

		public Integer getDefaultProductionDateUpper() {
			if(defaultProductionDateUpper == null) {
				try {
					defaultProductionDateUpper = Integer.parseInt(goodsQualitySetting.get("defaultProductionDateUpper"));
				} catch (NumberFormatException e) {
					defaultProductionDateUpper = 1;
				}
			}

			return defaultProductionDateUpper;
		}

		public ProductionDateUnitEnum getDefaultProductionDateUnit() {
			return ProductionDateUnitEnum.WEEK;
		}
	}

	private void buildGoodsForSave(SaveGoodsContext context, GoodsBO goodsBO, LocalDateTime now) {
		goodsBO.setGoodsOwnerId(0L);
		if(goodsBO.getQmsFlag() == null) {
			goodsBO.setQmsFlag(false);
		}
		if(goodsBO.getQualityGuaranteePeriod() == null) {
			goodsBO.setQualityGuaranteePeriod(context.getDefaultQualityGuaranteePeriod());
		}
		if(Objects.isNull(goodsBO.getQualityGuaranteePeriodUnit())) {
			goodsBO.setQualityGuaranteePeriodUnit(context.getDefaultQualityGuaranteePeriodUnit().getCode());
		}
		if(goodsBO.getProductionDateLower() == null) {
			goodsBO.setProductionDateLower(context.getDefaultProductionDateLower());
		}
		if(goodsBO.getProductionDateUpper() == null) {
			goodsBO.setProductionDateUpper(context.getDefaultProductionDateUpper());
		}
		if(goodsBO.getProductionDateUnit() == null) {
			goodsBO.setProductionDateUnit(context.getDefaultProductionDateUnit().getCode());
		}
		goodsBO.setStatus(ApplyStatusEnum.START.getCode());
		goodsBO.setTenantId(UserContextHolder.getTenantId());
		goodsBO.setCreateUserId(UserContextHolder.getUserId());
		goodsBO.setCreateUserName(UserContextHolder.getUserName());
		goodsBO.setCreateTime(now);
		goodsBO.setUpdateUserId(UserContextHolder.getUserId());
		goodsBO.setUpdateUserName(UserContextHolder.getUserName());
		goodsBO.setUpdateTime(now);
	}
	
	@Override
	public Result<?> updateGoods(GoodsBO goodsBO) {
		GoodsBO found = goodsManager.getGoods(goodsBO.getGoodsId());
		if(Objects.isNull(found)) {
			return Result.ofNotFound();
		}

		found.setGoodsName(goodsBO.getGoodsName());
		found.setGoodsAbbr(goodsBO.getGoodsAbbr());
		found.setGoodsChineseName(goodsBO.getCategory());
		found.setUnit(goodsBO.getUnit());
		found.setSupplierId(goodsBO.getSupplierId());
		found.setSupplierCode(goodsBO.getSupplierCode());
		found.setOriginalGoodsCode(goodsBO.getOriginalGoodsCode());
		found.setCategory(goodsBO.getCategory());
		found.setQualityGuaranteePeriod(goodsBO.getQualityGuaranteePeriod());
		found.setQualityGuaranteePeriodUnit(goodsBO.getQualityGuaranteePeriodUnit());
		found.setDeliveryRequirement(goodsBO.getDeliveryRequirement());
		found.setStorageRequirement(goodsBO.getStorageRequirement());
		found.setProductionDateLower(goodsBO.getProductionDateLower());
		found.setProductionDateUpper(goodsBO.getProductionDateUpper());
		found.setProductionDateUnit(goodsBO.getProductionDateUnit());
		found.setMemo(goodsBO.getMemo());

		LocalDateTime now = LocalDateTime.now();
		found.setUpdateUserId(UserContextHolder.getUserId());
		found.setUpdateUserName(UserContextHolder.getUserName());
		found.setUpdateTime(now);
		int affectedRows = goodsManager.updateGoods(found);
		if (affectedRows > 0) {
			return Result.success();
		}
		return Result.ofErrorRowsAffected();
	}
	
	@Override
	public Result<?> deleteGoods(Long goodsId) {
		int affectedRows = goodsManager.deleteGoods(goodsId);
		if (affectedRows > 0) {
			return Result.success();
		}
		return Result.ofErrorRowsAffected();
	}
	
	@Override
	public GoodsBO getGoods(Long goodsId) {
		return goodsManager.getGoods(goodsId);
	}

	@Override
	public GoodsBO getGoodsByCode(String goodsCode, Integer status) {
		List<GoodsBO> list = goodsManager.listGoodsByCode(goodsCode, false);
		if(!CollectionUtils.isEmpty(list)) {
			GoodsBO goods = list.get(0);
			if(status != null && !Objects.equals(status, goods.getStatus())) {
				return null;
			}
			return goods;
		}
		return null;
	}

	@Override
	public GoodsBO getGoodsByFullCode(String goodsFullCode, Integer status) {
		List<GoodsBO> list = goodsManager.listGoodsByFullCode(goodsFullCode, false);
		if(!CollectionUtils.isEmpty(list)) {
			GoodsBO goods = list.get(0);
			if(status != null && !Objects.equals(status, goods.getStatus())) {
				return null;
			}
			return goods;
		}
		return null;
	}

	@Override
	public List<GoodsBO> listGoodsById(Collection<Long> collection) {
		return goodsManager.listGoodsById(collection);
	}
	
	@Override
	public List<GoodsBO> listGoods(GoodsQuery query) {
		return goodsManager.listGoods(query);
	}

	@Override
	public List<GoodsBO> listGoodsByCode(String goodsCode, Integer status, boolean fuzzy) {
		List<GoodsBO> list = goodsManager.listGoodsByCode(goodsCode, fuzzy);
		if(status != null && !CollectionUtils.isEmpty(list)) {
			return list.stream().filter(e -> Objects.equals(status, e.getStatus())).collect(Collectors.toList());
		}
		return list;
	}

	@Override
	public List<GoodsBO> listGoodsByFullCode(String goodsFullCode, Integer status, boolean fuzzy) {
		List<GoodsBO> list = goodsManager.listGoodsByFullCode(goodsFullCode, fuzzy);
		if(status != null && !CollectionUtils.isEmpty(list)) {
			return list.stream().filter(e -> Objects.equals(status, e.getStatus())).collect(Collectors.toList());
		}
		return list;
	}

	@Override
	public List<GoodsBO> listGoodsByAbbr(String goodsAbbr, Integer status, boolean fuzzy) {
		List<GoodsBO> list = goodsManager.listGoodsByAbbr(goodsAbbr, fuzzy);
		if(status != null && !CollectionUtils.isEmpty(list)) {
			return list.stream().filter(e -> Objects.equals(status, e.getStatus())).collect(Collectors.toList());
		}
		return list;
	}

	@Override
	public int countGoods(GoodsQuery query) {
		return goodsManager.countGoods(query);
	}

    @Override
    public Integer getCategory(String goodsCode) {
        Map<String, Integer> map;
        return (map = mapCategory(Arrays.asList(goodsCode))).containsKey(goodsCode) ? map.get(goodsCode) : null;
    }

    private GoodsCodeApi goodsCodeApi = new HolmesGoodsCodeImpl();

    @Override
    public Map<String, Integer> mapCategory(Collection<String> goodsCodeCollection) {
        Map<String, Integer> map = new HashMap<>(16);
        if (goodsCodeCollection != null) {
            //TODO simple logic
            goodsCodeCollection.forEach(e -> {
                if (null != e) {
                    e = e.trim();
                    map.put(e, goodsCodeApi.getCategory(e));
                }
            });
        }
        return map;
    }

	@Override
	public String getPrimitiveGoodsCode(String goodsCode) {
		return goodsCodeApi.getPrimitiveGoodsCode(goodsCode);
	}

	interface GoodsCodeApi {
		Integer getCategory(String goodsCode);
		String getPrimitiveGoodsCode(String goodsCode);
	}

	class HolmesGoodsCodeImpl implements GoodsCodeApi {

    	final static String PREFIX_REAGENT = "HR";
		final static String PREFIX_CALIBRATION = "HC";
		final static String PREFIX_QUALITY = "HQ";
		final static String PREFIX_ANTIGEN = "HA";
		final static String PREFIX_MONOCLONAL_ANTIBODY = "HM";
		final static String PREFIX_POLYCLONAL_ANTIBODY = "HP";
		final static String PREFIX_ENZYME = "HE";
		final static String PREFIX_SUPPLEMENTARY = "HF";

		@Override
		public Integer getCategory(String goodsCode) {
			if(StringUtils.hasText(goodsCode)) {
				if (goodsCode.startsWith(PREFIX_REAGENT)
						|| goodsCode.startsWith(PREFIX_CALIBRATION)
						|| goodsCode.startsWith(PREFIX_QUALITY)) {
					return 1;
				} else if (goodsCode.startsWith(PREFIX_ANTIGEN)
						|| goodsCode.startsWith(PREFIX_MONOCLONAL_ANTIBODY)
						|| goodsCode.startsWith(PREFIX_POLYCLONAL_ANTIBODY)
						|| goodsCode.startsWith(PREFIX_ENZYME)
						|| goodsCode.startsWith(PREFIX_SUPPLEMENTARY)) {
					return 2;
				}
			}
			return 3;
		}

		@Override
		public String getPrimitiveGoodsCode(String goodsCode) {
			if(StringUtils.hasText(goodsCode)) {
				if(goodsCode.startsWith(PREFIX_MONOCLONAL_ANTIBODY)) {
					int index = goodsCode.indexOf("-");
					if(index > 0) {
						return goodsCode.substring(0, index);
					}
				} else if(goodsCode.startsWith(PREFIX_REAGENT)) {
					int index = goodsCode.lastIndexOf("-");
					if(index > 0) {
						return goodsCode.substring(0, index);
					}
				}
			}

			return goodsCode;
		}
	}

}
